﻿using ManagementApi.Converts;
using ManagementApi.Mvc;
using ManagementApi.Mvc.Authorization;
using ManagementApi.Mvc.Converters;
using ManagementApi.Mvc.Extensions;
using ManagementApi.Mvc.Filters;
using ManagementApi.Mvc.ModelBinders;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Modules.System.Settings;
using Modules.System.Settings.Entitys;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Jiguang;
using SqlSugar;
using System.Reflection;
using System.Text;

namespace ManagementApi
{
    public static class Builder
    {
        public static void AddManagementApi(this WebApplicationBuilder builder)
        {
            //追加配置
            builder.Configuration.AddJsonFile(Path.Combine(builder.Environment.ContentRootPath, "Config", "userRoutes.json"), optional: true, reloadOnChange: true);

            //基于文件系统的密钥存储库（持久性保持密钥）
            builder.Services.AddDataProtection()
                    .PersistKeysToFileSystem(new DirectoryInfo(Path.Combine(builder.Environment.ContentRootPath, "login-keys")));

            builder.Services.AddControllers(options =>
            {
                options.Filters.Add<GlobalExceptionFilter>();
                options.ModelBinderProviders.Insert(0, new PmSoftModelBinderProvider());//添加模型绑定器
            }).AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());

                //空字段不返回
                //options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
            });

            #region SqlSugar
            builder.Services.AddScoped<TransactionFilter>();
            builder.Services.AddHttpContextAccessor();
            builder.Services.AddSingleton<ISqlSugarClient>(s =>
            {
                SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig()
                {
                    DbType = DbType.MySql,
                    ConnectionString = builder.Configuration.GetValue("ConnectionStrings:DbConnection", string.Empty),
                    IsAutoCloseConnection = true,
                },
                db =>
                {
                    // 单例参数配置，所有上下文生效
                    db.Aop.OnLogExecuting = (sql, pars) =>
                    {
                        // 获取作IOC作用域对象
                        // var appServive = s.GetService<IHttpContextAccessor>();
                        // var obj = appServive?.HttpContext?.RequestServices.GetService<Log>();
                        // Console.WriteLine("AOP" + obj.GetHashCode());
                    };
                });
                return sqlSugar;
            });
            #endregion

            #region Jwt
           
            // 注册JWT服务 开启Bearer认证
            builder.Services.AddAuthentication("Bearer")
                .AddJwtBearer(options =>
            {
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.Events = new JwtBearerEvents
                {
                    OnAuthenticationFailed = context =>
                    {
                        // 如果过期，则把<是否过期>添加到，返回头信息中
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    }
                };
                string secretKey = builder.Configuration.GetValue<string>("Jwt:SecretKey") ?? string.Empty;
                //令牌验证参数
                options.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidateIssuer = true, //是否验证Issuer
                    ValidateAudience = true, //是否验证Audience
                    ValidateLifetime = true, //是否验证失效时间
                    ValidateIssuerSigningKey = true, //是否验证SecurityKey
                    ValidIssuer = builder.Configuration.GetValue<string>("Jwt:Issuer", string.Empty), //发行人Issuer
                    ValidAudience = builder.Configuration.GetValue<string>("Jwt:Audience", string.Empty), //订阅人Audience
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)), //SecurityKey
                    ClockSkew = TimeSpan.Zero, //允许的时间偏差
                    RequireExpirationTime = true,
                };
            }
            );

            #endregion Jwt

            #region Swagger

            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            //builder.Services.AddSwaggerGen();
            builder.Services.AddSwaggerGen(options =>
           {
               options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
               {
                   Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）",
                   Name = "Authorization",
                   In = ParameterLocation.Header,
                   Type = SecuritySchemeType.ApiKey
               });
               options.CustomSchemaIds(type => $"{type.Name}_{System.Guid.NewGuid()}");
               options.OperationFilter<SecurityRequirementsOperationFilter>();
               options.SwaggerDoc("v1", new OpenApiInfo { Title = "BuilderManagement API", Version = "v1", Description = "建筑工人管理系统" });
               var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
               var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
               options.IncludeXmlComments(xmlPath, true);
           });

            #endregion Swagger

            //权限认证
            builder.Services.AddScoped<IAuthorizer, DefaultAuthorizer>();

            builder.Services.AddSingleton<IAuthorizationHandler, PermissionCheckPolicyHandler>();
            builder.Services.AddAuthorization(options =>
            {
                options.AddPolicy("PermissionCheck",
                  policy => policy.Requirements.Add(new PermissionCheckPolicyRequirement()));
            });

            //入参模型有效性验证
            builder.Services.AddInvalidModelState();

            builder.Services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

            //注册当前用户状态提供器
            builder.Services.ConfigureStateProvider<CurrentUserStateProvider>();
            //builder.Services.ConfigureStateProvider<CurrentProjectCorpStateProvider>();

            //泛型注入
            builder.Services.AddScoped<SettingManager<CheckinWageStatusSettings>>();
            builder.Services.AddScoped<SettingRepository<CheckinWageStatusSettings>>();

            builder.Services.AddScoped<SettingManager<RetrievePasswordSetting>>();
            builder.Services.AddScoped<SettingRepository<RetrievePasswordSetting>>();

            builder.Services.AddScoped<SettingManager<WageMonthAmountSettings>>();
            builder.Services.AddScoped<SettingRepository<WageMonthAmountSettings>>();

            //注入基础组件
            builder.Services.AddPmSoftFrameWork(builder.Configuration, builder.Environment);

            //JieBa分词设置
            JiebaNet.Segmenter.ConfigManager.ConfigFileBaseDir = Path.Combine(Environment.CurrentDirectory, "Config", "ExtraDicts");

            //AutoMapper
            builder.Services.AddAutoMapper(typeof(AutoMapperProfiles));

            //Quartz
            // builder.Services.AddQuartz(RunAtServer.Service);

            //程序集注入
            builder.Services.AutoRegisterServicesFromAssembly("ManagementApi");
            builder.Services.AutoRegisterServicesFromAssembly("Modules");

            //注册短信相关
            // builder.Services.AddScoped<ISMSService, LeXinSMSService>();

            builder.Services.AddHostedService<ApplicationHostedService>();

            builder.Services.AddScoped<IJiguangService, JiguangService>();

            //注入NPOI
            builder.Services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
        }
    }
}